# -*- mode: org; fill-column: 100; -*-
#+TITLE: Guile Time Functionality
#+STARTUP: content indent align inlineimages hideblocks entitiesplain nologdone nologreschedule nologredeadline nologrefile
#+KEYWORDS: GNU Guile time
#+DATE: <2021-03-13 Sat>
#+LANGUAGE: English
#+PRIORITIES: A E E
#+TODO: TODO WIP | DONE
#+OPTIONS: ^:{}
#+OPTIONS: H:10
#+OPTIONS: toc:nil
#+OPTIONS: tags:nil
#+OPTIONS: tasks:nil
#+OPTIONS: H:6
#+OPTIONS: p:nil
#+OPTIONS: pri:nil
#+OPTIONS: prop:nil
#+OPTIONS: todo:nil
#+OPTIONS: stat:nil
#+OPTIONS: |:t
#+OPTIONS: inline:nil
#+OPTIONS: title:nil
#+OPTIONS: author:nil
#+OPTIONS: date:nil

* Documentation

https://www.gnu.org/software/guile/manual/html_node/Time.html

* General

This guide will make use of the [[https://srfi.schemers.org/srfi-19/srfi-19.html][SRFI-19]] implementation in GNU Guile, which deals with time
calculations. The approach is similar to that in other languages. There are time objects, time
duration objects and date objects.

* Prerequisites

#+NAME: prerequisites
#+begin_src scheme :noweb yes
(import (srfi srfi-19))
#+end_src

#+RESULTS: prerequisites
: #<unspecified>

#+NAME: deftimeunits
#+begin_src scheme :noweb yes
(define SECOND 1)
(define MINUTE (* 60 SECOND))
(define HOUR (* 60 MINUTE))
#+end_src

#+NAME: deforgtimestampformat
#+begin_src scheme :noweb yes
(define org-timestamp-format "[~Y-~m-~d ~a ~H:~M]")
#+end_src

* Objects

#+begin_src scheme :noweb yes :results output :tangle srfi-19-objects.scm
<<prerequisites>>

(simple-format (current-output-port) "date: ~s\n" (current-date))
(simple-format (current-output-port) "date: ~s\n" (make-date 0 0 0 10 13 3 2021 0))
(simple-format (current-output-port) "time: ~s\n" (current-time time-utc))
(let* ([seconds 1]
       [minutes (* 60 seconds)]
       [hours (* 60 minutes)]
       [now (current-time time-utc)])
  (simple-format (current-output-port)
                 "duration: ~s\n"
                 (time-difference (add-duration now (make-time time-duration 0 (* 1 hours)))
                                  now)))
#+end_src

#+RESULTS:
: date: #<date nanosecond: 415048000 second: 15 minute: 54 hour: 4 day: 14 month: 3 year: 2021 zone-offset: 3600>
: date: #<date nanosecond: 0 second: 0 minute: 0 hour: 10 day: 13 month: 3 year: 2021 zone-offset: 0>
: time: #<time type: time-utc nanosecond: 415131000 second: 1615694055>
: duration: #<time type: time-duration nanosecond: 0 second: 3600>

* Time format

For a list of format specifiers see [[https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#Formatting-Calendar-Time][Formatting Calendar Time]].

#+NAME: deftimediff
#+begin_src scheme :noweb yes :results output drawer replace :exports none
<<prerequisites>>

<<deforgtimestampformat>>

<<deftimeunits>>

(define duration->time-utc
  (λ (duration)
    (make-time time-utc
               (time-nanosecond duration)
               (time-second duration))))

(define org-timestamp->time-utc
  (λ (timestamp-string)
    (let ([parsed-date (string->date timestamp-string org-timestamp-format)])
          (date->time-utc parsed-date))))

(define org-time-duration
  (λ (org-timestamp-1 org-timestamp-2)
    (time-difference (org-timestamp->time-utc org-timestamp-2)
                     (org-timestamp->time-utc org-timestamp-1))))

(define duration->org-timestamp
  (λ (duration)
    (time-utc->date
     (duration->time-utc duration)
     ;; timezone offset, assume all with no offset
     0)))

(define duration->hours
  (λ (duration)
    (/ (time-second duration) HOUR)))
#+end_src

#+RESULTS: deftimediff
:results:
:end:

#+NAME: myorghours
#+begin_src scheme :noweb yes :var org-timestamp-1="[2021-01-01 Fri 00:00]", org-timestamp-2="[2021-01-01 Fri 01:00]" :results output drawer replace :exports none
<<deftimediff>>

(number->string
 (duration->hours
  (org-time-duration org-timestamp-1
                     org-timestamp-2)))
#+end_src

#+RESULTS: myorghours
:results:
ice-9/boot-9.scm:1669:16: In procedure raise-exception:
Wrong type to apply: #<syntax-transformer time-second>

Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]>
:end:

#+NAME: allinone
#+begin_src scheme :noweb yes :var org-timestamp-1="[2021-01-01 Fri 00:00]", org-timestamp-2="[2021-01-01 Fri 01:00]" :results output drawer replace :exports none
(import (srfi srfi-19))

(define SECOND 1)
(define MINUTE (* 60 SECOND))
(define HOUR (* 60 MINUTE))

(define org-timestamp-format "[~Y-~m-~d ~a ~H:~M]")

(define duration->time-utc
  (λ (duration)
    (make-time time-utc
               (time-nanosecond duration)
               (time-second duration))))

(define org-timestamp->time-utc
  (λ (timestamp-string)
    (let ([parsed-date (string->date timestamp-string org-timestamp-format)])
          (date->time-utc parsed-date))))

(define org-time-duration
  (λ (org-timestamp-1 org-timestamp-2)
    (time-difference (org-timestamp->time-utc org-timestamp-2)
                     (org-timestamp->time-utc org-timestamp-1))))

(define duration->org-timestamp
  (λ (duration)
    (time-utc->date
     (duration->time-utc duration)
     ;; timezone offset, assume all with no offset
     0)))

(define duration->hours
  (λ (duration)
    (/ (time-second duration) HOUR)))

(number->string
 (duration->hours
  (org-time-duration org-timestamp-1
                     org-timestamp-2)))
#+end_src

** WIP Usage in org-mode

|   | timestamp 1            | timestamp 2            | result |
|---+------------------------+------------------------+--------|
| # | [2021-03-14 Sun 03:50] | [2021-03-14 Sun 03:55] |        |
| # | [2021-03-14 Sun 03:50] | [2021-03-14 Sun 03:50] | nil    |
| # | [2021-03-14 Sun 03:50] | [2021-03-14 Sun 03:50] |        |
#+TBLFM: $4='(org-sbe "allinone" (org-timestamp-1 $2) (org-timestamp-2 $$3))

** TODO Usage

#+begin_src scheme :noweb yes
<<def-time-diff>>

(simple-format (current-output-port)
               "formatted output: ~s"
               (my-org-duration-format
                (time-difference (current-time time-utc)
                                 (add-duration (current-time time-utc)
                                               (make-time time-duration 0 (* 1 hours))))))
#+end_src

#+RESULTS:
